package sim;

import static java.lang.Math.PI;
import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.hypot;
import static java.lang.Math.sin;

import java.util.Random;



public class Vec2
{
	private final static Random random = new Random();

    public Vec2(double x,double y)
    {
        this.x=x;
        this.y=y;
    }
    public Vec2(Vec2 vec)
    {
        this.x=vec.x;
        this.y=vec.y;
    }
	static double Distance2(final Vec2 v1,final Vec2 v2)
    {
        return v1.Sub(v2).Mag2();
    }
    static double Distance(final Vec2 v1,final Vec2 v2)
    {
            return hypot(v1.x-v2.x,v1.y-v2.y);
    }
    
    public final double x,y;
    
    public final double GetX() {
        return x;
    }
    public final double GetY() {
        return y;
    }
	public static Vec2 randomVec2(double maxMagnitude) 
	{
		double magnitude = random.nextDouble()*maxMagnitude;
		return randomDirectionVec2(magnitude);
	}
	public static Vec2 randomDirectionVec2(double magnitude) 
	{
		double angle = random.nextDouble()*Math.PI*2;
		return specifiedDirectionVec2(magnitude,angle);
	}
	public static Vec2 specifiedDirectionVec2(double magnitude, double angle) 
	{
		while(angle>2*Math.PI)
		{
			angle-=2*Math.PI;
		}
		double x = Math.cos(angle)*magnitude;
		double y = Math.sin(angle)*magnitude;
		return new Vec2(x,y);
	}
	public static double divideCircleIntoAngleSlices(int numberOfSlices)
	{
		return 2*Math.PI/numberOfSlices;
	}
	public static Vec2 randomSliceAngleVector(int numberOfSlices, double maxMagnitude)
	{
		double fullAngleSlice=divideCircleIntoAngleSlices(numberOfSlices);
		double angle = fullAngleSlice*random.nextDouble();
		double magnitude = random.nextDouble()*maxMagnitude;
		return specifiedDirectionVec2(magnitude,angle);
	}
	
    public static Vec2 Add(Vec2 v1,Vec2 v2)
    {
        return new Vec2(v1.x+v2.x,v1.y+v2.y);
    }
    public static Vec2 Sub(Vec2 v1,Vec2 v2)
    {
        return new Vec2(v1.x-v2.x,v1.y-v2.y);
    }
    public static double Dot(Vec2 v1,Vec2 v2)
    {
        return v1.x*v2.x+v1.y*v2.y;
    }
    public static Vec2 Scale(Vec2 v1,double scale)
    {
        return new Vec2(v1.x*scale,v1.y*scale);
    }
    
    /**
     * Assumes counter-clockwise is positive ie. if v2 is counter-clockwise from
     * v1 then the result will be positive.
     * @author Stephen Pheiffer
     * @param v1
     * @param v2
     * @return sin of angle between v1 and v2.
     */
    public static double Cross(Vec2 v1, Vec2 v2)
    {
        return (v1.x * v2.y) - (v1.y * v2.x);
    }
    public boolean equals(Vec2 v1)
    {
        return v1.x==x && v1.y==y;
        
    }
    public Vec2 Add( Vec2 v2)
    {
        return new Vec2(x+v2.x,y+v2.y);
    }
    public Vec2 Sub(Vec2 v2)
    {
        return new Vec2(x-v2.x,y-v2.y);
    }
    public double Dot(Vec2 v2)
    {
        return x*v2.x+y*v2.y;
    }
    public Vec2 Scale(double scale)
    {
        return new Vec2(x*scale,y*scale);
    }
    /**
     * Get orthogonal vector (rotated clockwise)
     * @author Stephen Pheiffer
     * @return
     */
    public Vec2 Ortho()
    {
        return new Vec2(-y,x);
    }
    public double Mag2()
    {
        return x*x+y*y;
    }
    public double Mag()
    {
        return hypot(x,y);
    }
    public Vec2 Unit()
    {
        return Scale(1.0/this.Mag());
    }
    public Vec2 Rotate(double angle)
    {
        return new Vec2(x*cos(angle)-y*sin(angle),x*sin(angle)+y*cos(angle));
    }
    public Vec2 Rotate(double cosAngle,double sinAngle)
    {
        return new Vec2(x*cosAngle-y*sinAngle,x*sinAngle+y*cosAngle);
    }
    public double getAngle()
    {
        return atan2(y,x);
    }
    public double getAngleDifference(Vec2 v2)
    {
        double angle;
        angle = v2.getAngle() - getAngle();
        if(angle < 0.0)
            angle += 2 * PI;
        return angle;
    }

}
